package com.xs.designpattern;

import lombok.extern.slf4j.Slf4j;

import java.util.Stack;

/**
 * @author xs
 */
@Slf4j
public class Main {
    public static void main(String[] args) {
        // 孩子在学校学习一些基础数学定义我们想要解析的数学字符串
        final String tokenString = "4 3 2 - 1 + *";

        // 堆栈保存已解析的表达式
        Stack<Expression> stack = new Stack<>();

        // 对字符串进行标记并一一检查它们
        String[] tokenList = tokenString.split(" ");
        for (String s : tokenList) {
            if (isOperator(s)) {
                // 当遇到运算符时，我们期望可以从堆栈顶部弹出数字
                Expression rightExpression = stack.pop();
                Expression leftExpression = stack.pop();
                log.info("从堆栈左侧弹出: {} right: {}", leftExpression.interpret(), rightExpression.interpret());
                Expression operator = getOperatorInstance(s, leftExpression, rightExpression);
                log.info("操作方式: {}", operator);
                int result = operator.interpret();
                // 运算结果压入栈顶
                Expression resultExpression = new NumberExpression(result);
                stack.push(resultExpression);
                log.info("将结果压入堆栈: {}", resultExpression.interpret());
            } else {
                // 数字被压入栈顶
                Expression i = new NumberExpression(s);
                stack.push(i);
                log.info("压入堆栈: {}", i.interpret());
            }
        }
        // 最后，最终结果位于栈顶
        log.info("结果: {}", stack.pop().interpret());
    }

    /**
     * 检查输入参数是否为运算符
     *
     * @param s 输入参数
     * @return 如果输入参数是运算符，则为 true
     */
    public static boolean isOperator(String s) {
        return s.equals("+") || s.equals("-") || s.equals("*");
    }

    /**
     * 根据参数返回正确的表达式
     *
     * @param s     输入参数
     * @param left  左边表达式
     * @param right 右边表达式
     * @return 表达式
     */
    public static Expression getOperatorInstance(String s, Expression left, Expression right) {
        switch (s) {
            case "+":
                return new PlusExpression(left, right);
            case "-":
                return new MinusExpression(left, right);
            default:
                return new MultiplyExpression(left, right);
        }
    }
}